﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Net;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;
using System.Windows;

namespace SynchronizedPlayer {
	class NetReceiver : IDisposable {
		const uint MAX_BUF_SIZE = 256;
		const int MAX_CONNECTIONS_ALLOWED = 10;

		Socket _listener;
		ConcurrentQueue<Command> _rcvQueue;
		IPEndPoint _localEndPoint;

		ManualResetEvent _receiveFirstDone = new ManualResetEvent(false);
		ManualResetEvent _receiveFullDone = new ManualResetEvent(false);

		public NetReceiver(int port, ConcurrentQueue<Command> rcvQueue) {
			_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
			_localEndPoint = new IPEndPoint(IPAddress.Any, port);
			_listener.Bind(_localEndPoint);
			_rcvQueue = rcvQueue;
			_listener.Listen(MAX_CONNECTIONS_ALLOWED);
			_listener.BeginAccept(acceptCallback, _listener);

		}

		void acceptCallback(IAsyncResult res) {
			try {
				Socket listener = (Socket)res.AsyncState;
				Socket handler = listener.EndAccept(res);
				byte[] buffer = new byte[1];

				handler.BeginReceive(buffer, 0, 1, SocketFlags.None, receiveFirstCallback, new Tuple<Socket, byte[]>(handler, buffer));
				_receiveFirstDone.WaitOne();
			} catch (Exception e) {
				//MessageBox.Show("Check your internet connection and settings (ip address and port)", "Connection error!",
				//	MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}
		void receiveFirstCallback(IAsyncResult res) {
			try {
				Socket listener = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item1;
				if (listener.EndReceive(res) == 1) {
					_receiveFirstDone.Set();
					byte[] buffer = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item2;
					Socket handler = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item1;
					byte size = buffer[0];
					byte[] newbuffer = new byte[size];
					handler.BeginReceive(newbuffer, 0, size, SocketFlags.None, receiveFullCallback, new Tuple<Socket, byte[]>(handler, newbuffer));
					_receiveFullDone.WaitOne();
				}
			} catch (Exception e) {
				//MessageBox.Show("Check your internet connection and settings (ip address and port)", "Connection error!",
				//	 MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}

		void receiveFullCallback(IAsyncResult res) {

			try {
				Socket listener = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item1;
				byte[] buffer = ((Tuple<Socket, byte[]>)(res.AsyncState)).Item2;
				listener.EndReceive(res);
				_receiveFullDone.Set();
				_rcvQueue.Enqueue(Command.Parse(buffer));

				listener.Disconnect(true);

				_listener.Listen(MAX_CONNECTIONS_ALLOWED);
				_listener.BeginAccept(acceptCallback, _listener);
			} catch (Exception e) {
				//MessageBox.Show("Check your internet connection and settings (ip address and port)", "Connection error!",
				//	MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}

		public void Dispose() {
			_listener.Close();
		}
	}
}

